﻿using Facebook;
using System;
using SpaceNeedle.City6473.Web.Data.Repositories;
using SpaceNeedle.City6473.Web.Data;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using LinqToTwitter;
using System.Web.Mvc;
using System.Threading.Tasks;
using System.Data.Entity.Validation;
using SpaceNeedle.City6473.Web.Data.Helpers;
using SpaceNeedle.City6473.Web.Data.Models;
using SpaceNeedle.City6473.WebSite.Security.Mvc;
using System.Web.Routing;
using SpaceNeedle.City6473.WebSite.Models;


namespace SpaceNeedle.City6473.WebSite.Controllers
{
    public class AuthenticationController : GlobalController
    {
        #region ALL

        // GET: Authentication
        public ActionResult Index()
        {
            var model = new AuthenticationModel();
            
            model.AccentColor = "red";
            model.Platform = Platforms.WP8;
            model.Theme = Themes.Dark;

            try
            {
                if (!string.IsNullOrEmpty(Request.QueryString["accentColor"]))
                {
                    model.AccentColor = Request.QueryString["accentColor"];
                }

                if (!string.IsNullOrEmpty(Request.QueryString["platform"]))
                {
                    model.Platform = (Platforms)Enum.Parse(typeof(Platforms), Request.QueryString["platform"]);
                }

                if (!string.IsNullOrEmpty(Request.QueryString["theme"]))
                {
                    model.Theme = (Themes)Enum.Parse(typeof(Themes), Request.QueryString["theme"]);
                }
            }
            catch { }

            return View(model);
        }

        public ActionResult Success(string provider, Guid ID = new Guid())
        {
            return View();
        }

        public ActionResult Error()
        {
            return View();
        }

        #endregion

        #region Facebook
        public static string GetAppAccessToken()
        {
            var fb = new FacebookClient();
            dynamic result = fb.Get("oauth/access_token", new
            {
                client_id = "671908762862171",
                client_secret = "ded16f1ccdaf696c97cc2753d65195ab",
                grant_type = "client_credentials"
            });

            return result.access_token;
        }

        private Uri RedirectUri
        {
            get
            {
                var uriBuilder = new UriBuilder(Request.Url);
                uriBuilder.Query = null;
                uriBuilder.Fragment = null;
                uriBuilder.Path = Url.Action("FacebookCallBack");
                return uriBuilder.Uri;
            }
        }

        public ActionResult Facebook()
        {
            var fb = new FacebookClient();
            var loginUrl = fb.GetLoginUrl(new
            {
                client_id = "671908762862171",
                client_secret = "ded16f1ccdaf696c97cc2753d65195ab",
                redirect_uri = RedirectUri.AbsoluteUri,
                response_type = "code",
                scope = "read_stream,publish_actions,user_about_me,email" // Add other permissions as needed
            });

            return Redirect(loginUrl.AbsoluteUri);
        }

        public ActionResult FacebookCallBack(string code)
        {
            try
            {
                //User Token
                var fb = new FacebookClient();
                dynamic result = fb.Post("oauth/access_token", new
                {
                    client_id = "671908762862171",
                    client_secret = "ded16f1ccdaf696c97cc2753d65195ab",
                    redirect_uri = RedirectUri.AbsoluteUri,
                    code = code
                });

                var accessToken = GetLongAcessToken(result.access_token);
                DateTime tokenDate = GetTokenExpirationDate(GetAppAccessToken(), accessToken);

                //Get User
                dynamic fbUser = fb.Get("me", new
                {
                    access_token = accessToken
                });

                //Get User Image
                dynamic fbUserImage = fb.Get("me/picture", new
                {
                    redirect = false,
                    access_token = accessToken
                });

                //Insert User
                UserRepository tokenRepository = new UserRepository();

                string fbUserId = fbUser.id;
                var dbUser = tokenRepository.GetAll().Where(x => x.ProviderId == fbUserId).FirstOrDefault();

                if (dbUser == null)
                {
                    Web.Data.Models.User user = new Web.Data.Models.User();

                    user.Id = Guid.NewGuid();
                    user.Name = fbUser.name;
                    user.Picture = fbUserImage.data.url;
                    user.Email = fbUser.email;
                    user.ProviderId = fbUserId;
                    user.provider = "Facebook";
                    user.ProviderToken = accessToken;
                    user.TokenExpirationDate = tokenDate;

                    tokenRepository.Insert(user);

                    return RedirectToAction("Success", "Authentication", new {provider = user.provider, ID = user.Id});
                }
                else
                {
                    dbUser.Name = fbUser.name;
                    dbUser.ProviderToken = accessToken;
                    dbUser.TokenExpirationDate = tokenDate;
                    dbUser.Picture = fbUserImage.data.url;

                    tokenRepository.Update(dbUser);

                    return RedirectToAction("Success", "Authentication", new { provider = dbUser.provider, ID = dbUser.Id });
                }
            }
            catch 
            {
                return RedirectToAction("Error", "Authentication");
            }
        }

        public string GetLongAcessToken(string shortToken)
        {
            var longToken = "";

            FacebookClient fbcl = new FacebookClient(shortToken);
            fbcl.AccessToken = shortToken;
            fbcl.AppId = "671908762862171";
            fbcl.AppSecret = "ded16f1ccdaf696c97cc2753d65195ab";

            //try to get longer token
            try
            {
                dynamic result = fbcl.Get(string.Format("oauth/access_token?client_id={0}&client_secret={1}&grant_type=fb_exchange_token&fb_exchange_token={2}", fbcl.AppId, fbcl.AppSecret, shortToken));
                longToken = result.access_token;
            }
            catch
            {
                dynamic result = fbcl.Get(string.Format("oauth/access_token?client_id={0}&client_secret={1}&grant_type=fb_exchange_token&fb_exchange_token={2}", fbcl.AppId, fbcl.AppSecret, shortToken));
                longToken = result.access_token;
            }

            return longToken;
        }

        public DateTime GetTokenExpirationDate(string appAcessToken, string longUserAcessToken)
        {
            FacebookClient client = new FacebookClient();
            dynamic result = client.Get("debug_token", new
            {
                input_token = longUserAcessToken,
                access_token = appAcessToken
            });
            DateTime date = DateTime.Now.AddSeconds(Convert.ToDouble(result.data.expires_at));

            return date;
        }

        public Boolean SendPost(Web.Data.Models.User user, Guid requestItemId, string permaLink)
        {

            var client = new FacebookClient(user.ProviderToken);

            var postparameters = new Dictionary<string, object>();
            postparameters["message"] = permaLink;
            postparameters["link"] = permaLink;

            var result = client.Post("/me/feed", postparameters);

            if (result == null)
            {
                return false;
            }

            return true;
        }

        #endregion

        #region Twitter

        public async Task<ActionResult> BeginAsync()
        {
            try
            {
                var auth = new MvcAuthorizer
                {
                    CredentialStore = new SessionStateCredentialStore
                    {
                        ConsumerKey = "pgwE76oDEAiXKeHiLSXK0xcsz",
                        ConsumerSecret = "WPNsUw0q9Zxv2JuQvuEaPwnJaEJOq85SelzbYcLsJW7sms4Pe0"
                    }
                };
                string twitterCallbackUrl = Request.Url.ToString().Replace("Begin", "Complete");
                return await auth.BeginAuthorizationAsync(new Uri(twitterCallbackUrl));
            }
            catch(Exception ex) {
                return RedirectToAction("Error", "Authentication", new { ex = ex.Message });
            }
        }

        public async Task<ActionResult> CompleteAsync()
        {
            try
            {
                var auth = new MvcAuthorizer
                {
                    CredentialStore = new SessionStateCredentialStore()
                };
                await auth.CompleteAuthorizeAsync(Request.Url);

                //Insert User
                var credentials = auth.CredentialStore;
                UserRepository repository = new UserRepository();

                string twUserId = credentials.UserID.ToString();
                var dbUser = repository.GetAll().Where(x => x.ProviderId == twUserId).FirstOrDefault();

                if (dbUser == null)
                {
                    Web.Data.Models.User user = new Web.Data.Models.User();

                    user.Id = Guid.NewGuid();
                    user.Name = credentials.ScreenName;
                    user.Picture = await GetTwitterProfileImage(Convert.ToUInt64(twUserId));
                    user.ProviderId = twUserId;
                    user.provider = "Twitter";
                    user.ProviderToken = credentials.OAuthToken;
                    user.ProviderTokenSecret = credentials.OAuthTokenSecret;

                    repository.Insert(user);

                    return RedirectToAction("Success", "Authentication", new { provider = user.provider, ID = user.Id });
                }
                else
                {
                    dbUser.Name = credentials.ScreenName;
                    dbUser.ProviderToken = credentials.OAuthToken; //credentials.OAuthTokenSecret;
                    dbUser.Picture = await GetTwitterProfileImage(Convert.ToUInt64(dbUser.ProviderId));
                    repository.Update(dbUser);

                    return RedirectToAction("Success", "Authentication", new { provider = dbUser.provider, ID = dbUser.Id });
                }
            }
            catch(Exception ex)
            {
                return RedirectToAction("Error", "Authentication", new { ex = ex.Message });
            }
        }
        

        public async Task<string> GetTwitterProfileImage(ulong userID)
          {
              try
              {
                  var auth = new MvcAuthorizer
                    {
                        CredentialStore = new SessionStateCredentialStore()
                    };

                  var ctx = new TwitterContext(auth);

                  var users = await (from tweet in ctx.User
                                     where tweet.Type == UserType.Show &&
                                           tweet.UserID == userID
                                     select tweet).SingleOrDefaultAsync();

                  if (users != null)
                  {
                      return users.ProfileImageUrl;
                  }
                  return string.Empty;
              }
              catch
              {
                  return string.Empty;
              }
          }

        public async Task<Boolean> SendTweet(Web.Data.Models.User user, Guid requestItemId, string permaLink)
        {
            var auth = new MvcAuthorizer
            {
                CredentialStore = new SessionStateCredentialStore
                {
                    ConsumerKey = "pgwE76oDEAiXKeHiLSXK0xcsz",
                    ConsumerSecret = "WPNsUw0q9Zxv2JuQvuEaPwnJaEJOq85SelzbYcLsJW7sms4Pe0",
                    OAuthToken = user.ProviderToken,
                    OAuthTokenSecret = user.ProviderTokenSecret,
                    ScreenName = user.Name,
                    UserID = Convert.ToUInt64(user.ProviderId)
                }
            };
            var ctx = new TwitterContext(auth);

            var status = permaLink;
            var tweet = await ctx.TweetAsync(status);

            if (tweet == null)
            {
                return false;
            }

            return true;
        }

        #endregion

        #region Email

        public ActionResult Email()
        {
            return View();
        }

        public ActionResult Validate()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Email(string email)
        {
            try
            {
                CodesRepository repository = new CodesRepository();
                var code = repository.GetAll().Where(x => x.Value.Contains(email)).FirstOrDefault();
                string key;

                if (code == null)
                {
                    key = GenerateKey();

                    Code co = new Code();
                    co.Id = Guid.NewGuid();
                    co.Value = string.Format("{0}-{1}", key, email); ;

                    repository.Insert(co);
                }
                else
                {
                    key = code.Value.Split('-')[0];
                }
                Mail.Send(email, "Confirmação de Email", "Seu código é: " + key);

                return RedirectToAction("Validate", "Authentication");
            }
            catch
            {
                return RedirectToAction("Error", "Authentication");
            }
        }

        [HttpPost]
        public ActionResult Validate(FormCollection collection)
        {
            var name = collection["name"];
            var email = collection["emailValidate"];
            var value = collection["code"];

            value = string.Format("{0}-{1}", value, email);
            try
            {
                CodesRepository codeRepository = new CodesRepository();
                UserRepository userRepository = new UserRepository();

                var code = codeRepository.GetAll().Where(x => x.Value == value).FirstOrDefault();

                if(code == null)
                {
                    return RedirectToAction("Error", "Authentication");
                }

                var dbUser = userRepository.GetAll().Where(x => x.ProviderId == email).FirstOrDefault();

                if (dbUser == null)
                {
                    Web.Data.Models.User user = new Web.Data.Models.User();

                    user.Id = Guid.NewGuid();
                    user.Name = name;
                    user.Email = email;
                    user.ProviderId = email;
                    user.provider = "Email";

                    userRepository.Insert(user);
                    codeRepository.Delete(code);

                    return RedirectToAction("Success", "Authentication", new { provider = user.provider, ID = user.Id });
                }
                else
                {
                    dbUser.Name = name;

                    userRepository.Update(dbUser);
                    codeRepository.Delete(code);

                    return RedirectToAction("Success", "Authentication", new { provider = dbUser.provider, ID = dbUser.Id });
                }
            }
            catch
            {
                return RedirectToAction("Error", "Authentication");
            }
        }

        public string GenerateKey()
        {
            CodesRepository codeRepository = new CodesRepository();
            string key;

            while (true)
            {
                key = new Random().Next(1000, 9999).ToString();

                var code = codeRepository.GetAll().Where(x => x.Value == key).FirstOrDefault();

                if(code == null)
                {
                    break;
                }
            }
            return key;
        }

        #endregion

        #region Anonymous

        public ActionResult Anonymous(string userId)
        {
            try
            {
                Guid id = new Guid(userId);

                UserRepository repository = new UserRepository();
                var user = repository.GetById(id);

                if(user == null)
                {
                    return RedirectToAction("Error", "Authentication");
                }

                return RedirectToAction("Success", "Authentication", new { provider = user.provider, ID = user.Id });
            }
            catch
            {
                return RedirectToAction("Error", "Authentication");
            }
        }

        #endregion
    }
}
